package cn.tedu.review;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**本类用复写售票案例实现方案2*/
public class TestRunnable {
    public static void main(String[] args) {
        //4.创建自定义类对象，作为唯一的业务对象
        TicketRunnable tr = new TicketRunnable();
        //5.创建多个线程对象，并且把唯一的业务对象交给线程对象来干活
//        Thread t1 = new Thread(tr);
//        Thread t2 = new Thread(tr);
//        Thread t3 = new Thread(tr);
//        Thread t4 = new Thread(tr);
        //6.以多线程的方式启动线程
//        t1.start();
//        t2.start();
//        t3.start();
//        t4.start();
        /**Executors是用来辅助创建线程池的工具类对象
         * 常用方法是newFixedThreadPool(int)，这个方法可以创建指定数目的线程池对象
         * 创建出来的线程池对象是ExecutorService：这个池子用来新建/启动/存储/销毁线程*/
        ExecutorService pool = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 5; i++) {
            /**execute()是让线程池中的线程来执行业务，每次调用这个方法
             * 都会将一个线程加入到就绪队列中，但注意，具体执行还得看OS是否选中*/
            pool.execute(tr);/**本方法的参数就是我们的业务，也就是业务类对象tr*/
        }
    }

}
/**1.多线程出现数据安全问题的原因：多线程程序+共享数据+多条语句操作共享数据
 *
 * 操作共享数据
 * 2.同步锁：相当于给容易出现问题的代码加了一把锁，包裹了所有可能会出现数据安全的代码
 * 加锁之后就有了同步（排队）的效果,加锁需要考虑：
 * 锁的范围：不能太大，太大，干啥都得排队，效率低
 *         不能太小，太小，锁不住，还是会出现安全隐患
 *  并且注意！！！多个线程间，必须使用同一把锁，否则锁不住！！！*/
//1.自定义多线程售票
class TicketRunnable implements Runnable{
    //3.完成业务
//    Object o = new Object();
//    Cat c = new Cat();
    int tickets = 100;
    //2.添加接口中未实现的方法，里面是我们的业务
    @Override
    public void run() {
        while (true){
            /**3.同步代码块：synchronized(唯一的锁对象){会出现安全隐患的所有代码}
             * 同步代码块在同一时刻，同一资源只会被一个线程对象独享*/
            /**这种写法不对，相当于每个线程进来时，执行这句话都会new一个新的锁对象
             * 多个线程间使用的并不是同一个唯一的锁对象，所以锁不住*/
//            synchronized (new Object()){
            //修改同步代码块的锁对象成为成员变量o，因为锁对象必须唯一
            synchronized (TicketRunnable.class){
                if (tickets > 0){
                    //7.让线程休眠，增加出错率
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"="+tickets--);

                }
                if (tickets <= 0) break;
            }


        }
    }
}
class Cat{}